package org.softmed.rest.server.test.creators;

import java.util.ArrayList;
import java.util.List;

import org.restlet.data.Response;
import org.softmed.rest.server.test.TestCreator;
import org.softmed.rest.server.test.creators.testcases.parameters.DeleteField;
import org.softmed.rest.server.test.creators.testcases.parameters.EditFieldNameText;
import org.softmed.rest.server.test.creators.testcases.parameters.GetFieldNameText;
import org.softmed.rest.server.test.creators.testcases.parameters.PostWrongMediaTypeField;
import org.softmed.rest.server.test.creators.testcases.parameters.PutWrongMediaTypeField;
import org.softmed.rest.server.test.creators.testcases.parameters.SetFieldNameText;
import org.softmed.rest.server.test.scenario.TestCase;
import org.softmed.rest.server.test.scenario.TestScenario;
import org.softmed.rest.server.test.util.TestUtil;

public abstract class AbstractTestScenarioCreator implements TestCreator {

	public static final String XML = "application/xml";
	public static final String TEXT = "text/plain";

	public static final String POST = "POST";
	public static final String PUT = "PUT";
	public static final String GET = "GET";
	public static final String DELETE = "DELETE";

	protected TestUtil util = new TestUtil();

	protected String serverURI;
	protected String baseURI;
	protected List<TestCase> cases;
	protected TestCase testCase;

	protected List<AbstractTestCaseCreator> caseTesters = new ArrayList<AbstractTestCaseCreator>();

	public AbstractTestScenarioCreator(String baseURI) {
		this.baseURI = baseURI;
	}

	protected String getURI() {
		return serverURI + baseURI;
	}

	@Override
	public TestScenario test(String uri) throws Throwable {
		this.serverURI = uri;
		TestScenario scenario = new TestScenario();
		cases = scenario.getCases();

		test(scenario, uri);
		return scenario;
	}

	protected abstract void test(TestScenario scenario, String uri)
			throws Throwable;

	protected void testCases(String uri) throws Throwable {
		String elementURI = null;
		for (AbstractTestCaseCreator tester : caseTesters) {
			try {
				tester.setCreator(this);
				elementURI = tester.testCaseProxy(uri, elementURI);
			} catch (Throwable t) {
				t.printStackTrace();
			}
		}
	}

	public Response get(String uri) throws Throwable {
		createTestResult();
		return util.get(uri);
	}

	public Response delete(String uri) throws Throwable {
		createTestResult();
		return util.delete(uri);
	}

	public Response put(String uri, String mimeType, String content)
			throws Throwable {
		createTestResult();
		return util.put(uri, mimeType, content);
	}

	public Response post(String uri, String mimeType, String content)
			throws Throwable {
		createTestResult();
		return util.post(uri, mimeType, content);
	}

	public Response getRelative(String uri) throws Throwable {
		String buri = getURI();
		if (uri != null)
			buri += uri;

		return get(buri);
	}

	public Response putRelative(String uri, String mimeType, String content)
			throws Throwable {
		String buri = getURI();
		if (uri != null)
			buri += uri;

		return put(buri, mimeType, content);
	}

	public Response postRelative(String uri, String mimeType, String content)
			throws Throwable {
		String buri = getURI();
		if (uri != null)
			buri += uri;

		return post(buri, mimeType, content);
	}

	public Response deleteRelative(String uri, String mimeType, String content)
			throws Throwable {
		String buri = getURI();
		if (uri != null)
			buri += uri;

		return delete(buri);
	}

	public Response putRelativeXML(String uri, String content) throws Throwable {
		return putRelative(uri, XML, content);
	}

	public Response postRelativeXML(String uri, String content)
			throws Throwable {
		return postRelative(uri, XML, content);
	}

	public Response putRelativeTEXT(String uri, String content)
			throws Throwable {
		return putRelative(uri, TEXT, content);
	}

	public Response postRelativeTEXT(String uri, String content)
			throws Throwable {
		return postRelative(uri, TEXT, content);
	}

	public Response putRelativeXML(String content) throws Throwable {
		return putRelative(null, XML, content);
	}

	public Response postRelativeXML(String content) throws Throwable {
		return postRelative(null, XML, content);
	}

	public Response putRelativeTEXT(String content) throws Throwable {
		return putRelative(null, TEXT, content);
	}

	public Response postRelativeTEXT(String content) throws Throwable {
		return postRelative(null, TEXT, content);
	}

	public Response putXML(String uri, String content) throws Throwable {
		return put(uri, XML, content);
	}

	public Response postXML(String uri, String content) throws Throwable {
		return post(uri, XML, content);
	}

	public Response putTEXT(String uri, String content) throws Throwable {
		return put(uri, TEXT, content);
	}

	public Response postTEXT(String uri, String content) throws Throwable {
		return post(uri, TEXT, content);
	}

	public TestCase createTestResult() {
		testCase = new TestCase();
		util.setTestCase(testCase);
		cases.add(testCase);
		return testCase;
	}

	public void failedTestCase() {
		testCase.setSucess(false);
	}

	public TestUtil getUtil() {
		return util;
	}

	public List<TestCase> getCases() {
		return cases;
	}

	public TestCase getTestCase() {
		return testCase;
	}

	public List<AbstractTestCaseCreator> getCaseTesters() {
		return caseTesters;
	}

	protected void testStringField(String xmlRoot, String fieldName,
			String firstValue, String secondValue) {
		String value = firstValue;

		caseTesters.add(new GetFieldNameText(fieldName, null, true));
		caseTesters.add(new SetFieldNameText(xmlRoot, fieldName, value));
		caseTesters.add(new GetFieldNameText(fieldName, value, false));

		// error - try to edit a String field or primitive field to a XML value
		caseTesters.add(new PutWrongMediaTypeField(fieldName));
		caseTesters.add(new GetFieldNameText(fieldName, value, false));

		// error - post after it exists
		caseTesters.add(new SetFieldNameText(xmlRoot, fieldName, value, false,
				false));
		caseTesters.add(new GetFieldNameText(fieldName, value, false));

		value = secondValue;
		// change string text
		caseTesters.add(new EditFieldNameText(xmlRoot, fieldName, value));
		caseTesters.add(new GetFieldNameText(fieldName, value, false));

		caseTesters.add(new DeleteField(xmlRoot, fieldName));
		caseTesters.add(new GetFieldNameText(fieldName, null, false));

		// error - try to add a String field to a XML value
		caseTesters.add(new PostWrongMediaTypeField(fieldName));
		caseTesters.add(new GetFieldNameText(fieldName, null, false));

	}

	protected void testStringFieldOnAttribute(String xmlRoot, String fieldName,
			String firstValue, String secondValue) {
		String value = firstValue;

		caseTesters.add(new GetFieldNameText(fieldName, null, true));
		caseTesters.add(new SetFieldNameText(xmlRoot, fieldName, value, true,
				false));
		caseTesters.add(new GetFieldNameText(fieldName, value, false));

		// error - try to edit a String field or primitive field to a XML value
		caseTesters.add(new PutWrongMediaTypeField(fieldName));
		caseTesters.add(new GetFieldNameText(fieldName, value, false));

		// error - post after it exists
		caseTesters.add(new SetFieldNameText(xmlRoot, fieldName, value, false,
				false));
		caseTesters.add(new GetFieldNameText(fieldName, value, false));

		value = secondValue;
		// change string text
		caseTesters
				.add(new EditFieldNameText(xmlRoot, fieldName, value, false));
		caseTesters.add(new GetFieldNameText(fieldName, value, false));

		caseTesters.add(new DeleteField(xmlRoot, fieldName));
		caseTesters.add(new GetFieldNameText(fieldName, null, false));

		// error - try to add a String field to a XML value
		caseTesters.add(new PostWrongMediaTypeField(fieldName));
		caseTesters.add(new GetFieldNameText(fieldName, null, false));

	}

}
